#ifndef _NetworkInterfaceStructs_h_
#define _NetworkInterfaceStructs_h_

#include <buildspec.h>
#include <config.h>
#include <GSTenums.h>
#include <Geometry/SRS.h>
#include <Geometry/IGeometry.h>
#include <GSTCore/GST_Types.h>
#include <Utils/GSTVersion.h>
#include <transport/JsonFileEncoder.h>

#include <Client/ClientUtils/Network/ColorMap.hpp>
#include <Client/ClientUtils/Network/NetworkInterfaceExceptions.hpp>
#include <Client/ClientUtils/Network/TableAttributeVal.h>

#include <string>

#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

namespace GST {

//prototypes:
namespace ClientUtils {
	class IDataTable;
	class FeatureClassDetailedDesc;
	class GeoColumnDesc; 
	struct FeatureDesc;
	class FeatureClassDesc;
}
namespace Geometry {
	class ClientGeometry;
}

namespace ClientUtils
{
	using GST::GSTCore::GSTbox;
	
//helpers:
struct GST_API_EXPORT Host
{
	std::string ip;
	long port;
	std::string user, pwd;
	std::string sslCert;
	Host(const std::string& _url="", const long& _port=0, const std::string& _usr="", const std::string& _pwd="", const std::string & _sslCert="")
		: ip(_url), user(_usr), pwd(_pwd), sslCert(_sslCert)
	{
		port = _port>0 ? _port : 80;
	}
	void setParameters(const std::string& _url="", const long& _port=0, const std::string& _usr="", const std::string& _pwd="", const std::string & _sslCert="")
	{
		ip = _url;
		port = _port;
		user = _usr;
		pwd = _pwd;
		sslCert = _sslCert;
	}
	bool operator ==(const Host& other) const;
	bool operator !=(const Host& other) const;
	bool isAuth() const
	{
		return !user.empty();
	}
}; // struct Host
typedef boost::shared_ptr<Host> HostPtr;

struct GST_API_EXPORT KeyValueList
{
	typedef std::map<std::string, std::string> KVL;
	KVL list; 
	const std::string & getKey(const KVL::const_iterator & itr) { return itr->first; }
	const std::string & getValue(const KVL::const_iterator & itr) { return itr->second; }
};
typedef boost::shared_ptr<KeyValueList> KeyValueListPtr;

struct GST_API_EXPORT ServerInfo : public KeyValueList
{
	typedef KeyValueList::KVL::const_iterator const_iterator;

	ServerInfo() {}
	ServerInfo(const std::string& field, const std::string& value)
	{
		list[field] = value;
	}
	void push_back(const std::string& field, const std::string& value)
	{
		list[field] = value;
	}
	const_iterator begin() const { return this->list.begin(); }
	const_iterator end() const { return this->list.end(); }
	size_t size() const { return this->list.size(); }	
	static std::string getField(const const_iterator& i) { return i->first; }
	static std::string getValue(const const_iterator& i) { return i->second; }
};	
typedef boost::shared_ptr<ServerInfo> ServerInfoPtr;

enum class ZAxisDomain
{
	// The z-axis is height (unit=m), positive direction is up (elevation)
	Height,
	// The z-axis is time (unit=ms), positive direction is down (depth)
	Time,
};


class GST_API_EXPORT FeatureClassDesc
{

protected:
	std::string name;
	std::string owner;
	std::string geometryColumn;
	Geometry::IGeometry::GeometryType geomtype;
	Geometry::SRSPtr srs;
	int numberOfFeatures;
    long long id;
	ZAxisDomain zAxisDomain;

public:

    FeatureClassDesc();
	FeatureClassDesc(const std::string &fullClassName,
					 const std::string &geometryColumn,
					 const Geometry::IGeometry::GeometryType &geomtype,
					 Geometry::SRSPtr srs = Geometry::SRSPtr(),
					 int numberOfFeatures = -1,
					 const long long id = -1,
					 ZAxisDomain zAxisDomain = ZAxisDomain::Height);
	FeatureClassDesc(const std::string &name,
					 const std::string &owner,
					 const std::string &geometryColumn,
					 const Geometry::IGeometry::GeometryType &geomtype,
					 Geometry::SRSPtr srs = Geometry::SRSPtr(),
					 int numberOfFeatures = -1,
					 const long long id = -1,
					 ZAxisDomain zAxisDomain = ZAxisDomain::Height);

	///@name operators
	//@{
	bool contains(const FeatureDesc& feature) const;
	bool operator ==(const FeatureClassDesc& other) const;
	bool operator !=(const FeatureClassDesc& other) const;
	//@}

	///@name getters/setters
	//@{
	bool isPublic() const;
	std::string getFullName() const;
	std::string getGroup() const;
	std::string getGeometryColumn() const;
	void setGeometryColumn(std::string val);
	Geometry::IGeometry::GeometryType getGeomtype() const;
	void setGeomtype(Geometry::IGeometry::GeometryType val);
	std::string getOwner() const;
	void setOwner(std::string val);
	std::string getName() const;
	void setName(std::string val);
	GST::Geometry::SRSPtr getSrs() const;
	void setSrs(GST::Geometry::SRSPtr val);
	/**
	  * @returns optional member FeatureClassDesc::numberOfFeatures that counts the features in a feature class. 
	  * The counter is set by NetworkInterface::ListFeatureClasses().
	  * You can use FeatureClassDesc::isNumberOfFeaturesFetched() to check whether the counter is valid or not
	  */
	int getNumberOfFeatures() const;
	void setNumberOfFeatures(int val);
	/**
	  * @returns true if the counter numberOfFeatures is fetched from the database
	  */
	bool isNumberOfFeaturesFetched() const;
    void setID(const long long& val);
    long long getID() const;
	ZAxisDomain getZAxisDomain() const;
	void setZAxisDomain(ZAxisDomain zAxisDomain);
	//@}
};
typedef boost::shared_ptr<FeatureClassDesc> FeatureClassDescPtr;
typedef boost::ptr_vector<FeatureClassDesc> FeatureClassDescList;
typedef boost::shared_ptr<FeatureClassDescList> FeatureClassDescListPtr;


struct GST_API_EXPORT LockState
{
	enum LockType{FREE=2,OBJECT=4,PART=16};
	LockType state;

	LockState(const LockType & state)
		: state(state)
	{}
};
typedef boost::shared_ptr<LockState> LockStatePtr;

struct GST_API_EXPORT IndexState
{
	enum IndexStateType{IndexInvalid=-1, IndexUnavailable=0, IndexAvailable=1};
	IndexStateType state;

	IndexState(const IndexStateType & state)
		: state(state)
	{}
};
typedef boost::shared_ptr<IndexState> IndexStatePtr;


struct GST_API_EXPORT AccessLevel
{
	long level;
	std::string desc;

	AccessLevel(const long & lvl, const std::string& desc)
		: level(lvl), desc(desc)
	{}
};


typedef boost::shared_ptr<AccessLevel> AccessLevelPtr;
typedef std::vector<AccessLevelPtr> AccessLevelList;
typedef boost::shared_ptr<AccessLevelList> AccessLevelListPtr;

struct GST_API_EXPORT ServiceDescription
{
	long id;
	std::string name;
	std::string url;
	long accessLevelId;
	std::string user;
	std::string secret;
};

typedef boost::shared_ptr<ServiceDescription> ServiceDescriptionPtr;
typedef std::vector<ServiceDescription> ServiceDescrionList;
typedef boost::shared_ptr<ServiceDescrionList> ServiceDescrionListPtr;

enum class GeometryHullState {
	Unknown,
	Set,
	NotSet
};

struct GST_API_EXPORT FeatureDesc
{
	std::string name;
	int levelsAvaiable;
	long geometryId;
	FeatureClassDesc fclass;
	///@name optional information
	//@{
	LockStatePtr lockstate;
	GSTbox bbox;
	IndexStatePtr indexstate;
	GeometryHullState hullstate;
	//@}

	FeatureDesc() {}
	FeatureDesc(const std::string& name, const int& levelsAvaiable, const long& geometryId, const FeatureClassDesc& fclass, const GSTbox& bbox);

	///@name operators
	//@{
	bool operator ==(const FeatureDesc& other) const;
	bool operator !=(const FeatureDesc& other) const;
	//@}

	//typedef boost::shared_ptr<ICondition> ConditionPtr;		
	//std::vector<ConditionPtr> conditions;
};
typedef boost::shared_ptr<FeatureDesc> FeatureDescPtr;
typedef boost::ptr_vector<FeatureDesc> FeatureDescList;
typedef boost::shared_ptr<FeatureDescList> FeatureDescListPtr;

/**
	* Wrapper for the resulting data (get requests).
	*/
struct GST_API_EXPORT CrudeFeature
{

	FeatureDescPtr desc;
	boost::shared_array<unsigned char> binGeo;
	Geometry::IGeometry::RequestFormat geometryformat;
	Geometry::SRSPtr srs;
	Transport::GeometryData metaData;
		
	virtual std::string GetGeometry() = 0;
	virtual std::string GetPropertyDesc();
	virtual std::string GetPropertyVals() = 0;
	virtual std::string GetLockId() = 0;
	virtual Transport::GeometryData GetMetaData() const { return this->metaData; }
	virtual void parseMetaData( const std::string input );
	virtual boost::shared_array<unsigned char> GetBinaryGeometry() { return this->binGeo; }
	virtual TableAttributeValListPtr GetObjProperties() = 0;
};
typedef boost::shared_ptr<CrudeFeature> CrudeFeaturePtr;

struct GST_API_EXPORT QueryBox
{
	GSTCore::GSTbox box;
	double borderSize;
	Geometry::SRSPtr srs;

	QueryBox(const GSTCore::GSTbox& box, const double& borderSize, Geometry::SRSPtr srs)
		: box(box)
		, borderSize(borderSize)
		, srs(srs)
	{}	

	std::string GetCommaSeparatedMinMaxList() const;
	std::string GetBorderSize() const;
	Geometry::SRSPtr GetSRS() const;
};
typedef boost::shared_ptr<QueryBox> QueryBoxPtr;

/**
	* Configuration for the database. Inherit from here to make 
	* db type specific configuration.
	*
	* @todo may merge in future releases with Host and DB name/service name
	*/
struct GST_API_EXPORT DBConfig
{
	int max_reconnect_tries;
	bool operator ==(const DBConfig& other) const;
	bool operator !=(const DBConfig& other) const;

	virtual bool doCompare(const DBConfig& other) const;
	
	virtual ~DBConfig() {}
};
typedef boost::shared_ptr<DBConfig> DBConfigPtr;

struct GST_API_EXPORT EndPoint
{
	HostPtr host;
	DBConfigPtr dbconfig;
	Protocol protocol;
	std::string database;

	bool operator==( const EndPoint & other ) const;
	bool operator!=(const EndPoint& other) const;
};
typedef boost::shared_ptr<EndPoint> EndPointPtr;
// Creates a deep copy of ep, that doesn't share host/dbconfig ptrs of ep.
EndPoint deepCopy(const EndPoint &ep);

struct GST_API_EXPORT LockInfo
{
	std::string lockId;
	std::string user;
	std::string checkedOut;
	GST::LockType ltype;
};
typedef boost::shared_ptr<LockInfo> LockInfoPtr;
typedef std::vector<LockInfoPtr> LockInfoList;
typedef boost::shared_ptr<LockInfoList> LockInfoListPtr;

struct GST_API_EXPORT SurfacePoint
{
	double x;
	double y;
	bool valid;

	SurfacePoint();
	SurfacePoint(const double & px, const double & py);

	SurfacePoint & operator=(const SurfacePoint & other);
};

struct GST_API_EXPORT SurfaceLine
{
	SurfacePoint p1;
	SurfacePoint p2;

	SurfaceLine();
	SurfaceLine(const SurfacePoint & p1, const SurfacePoint & p2);

	SurfaceLine & operator=(const SurfaceLine & other);
};

//-----------------------------------------------------------------------------------------------------------
/**
  * @brief	stores result of one of the intersection function
  *
  * @param	intersecionImageFileName	file name including path 
  *                                     to resulting intersection image
  *
  * @param	legendImageFileName			file name including path
  *                                     to resulting legend image
  *										(optional) only if separate legend image
  *										was requested, empty otherwise
  *
  * @param	legendInfoJson				legend info in json format
  *
  * @see		NetworkInterface::SaveBoreholeImage
  * @see		NetworkInterface::SaveSectionImage
  * @see		NetworkInterface::SaveMapImage
  */
struct GST_API_EXPORT IntersectionInfo
{
	std::string intersecionImageFileName;
	std::string legendImageFileName;
	std::string legendInfoJson;
};
typedef boost::shared_ptr<IntersectionInfo> IntersectionInfoPtr;

struct GST_API_EXPORT PropertyAlias
{

	friend class boost::serialization::access; 

public:
	std::string aliasName;
	long accessLevelId;

	PropertyAlias(const std::string &aliasName, long accessLevelId)
		: aliasName(aliasName)
		, accessLevelId(accessLevelId)
	{

	}

	///default constructor for boost serialization support
	PropertyAlias()
		: aliasName("undefined")
		, accessLevelId(0)
	{

	}

private:
	template <typename Archive> 
	void serialize(Archive &ar, const unsigned int version) 
	{ 
		//If you change members here do not forget to increment object version (see bottom of this file)
		ar & boost::serialization::make_nvp("aliasName",aliasName); 
		ar & boost::serialization::make_nvp("accessLevelId",accessLevelId);
	} 
};
typedef boost::shared_ptr<PropertyAlias> PropertyAliasPtr;
//key: property name; value: alias
typedef std::map<std::string, PropertyAlias, Utils::UpperCaseCompare> PropertyAliasMap;
typedef boost::shared_ptr<PropertyAliasMap> PropertyAliasMapPtr;

typedef std::pair<std::string, std::string> webLogin;
struct GST_API_EXPORT dbLogin
{
    std::string user;
    std::string pw;
    std::string allowUpload;
    std::string allowSHPSection;
    long accessLevel;
    dbLogin()
        : user()
        , pw()
        , allowUpload()
        , accessLevel(-1)
        , allowSHPSection()
    {
    }
};
struct GST_API_EXPORT WebUserDesc
{
    long id;
    std::string login;
    std::string allowUpload;
    std::string allowSHPSection;
    long accessLevel;
    WebUserDesc(long id,
                const std::string &login,
                const std::string &allowUpload,
                const std::string &allowSHPSection,
                long accessLevel)
        : id(id)
        , login(login)
        , allowUpload(allowUpload)
        , allowSHPSection(allowSHPSection)
        , accessLevel(accessLevel)
    {
    }
};
typedef std::vector<WebUserDesc> WebuserDescList;
typedef boost::shared_ptr<WebuserDescList> WebuserDescListPtr;
//typedef std::tuple<std::string, std::string, std::string> dbLogin;
typedef std::tuple<std::string, std::string, std::string> webToDbMapping;
typedef std::vector<webToDbMapping> webToDbMappingList;

struct GST_API_EXPORT FeatureData
{
	FeatureDescPtr featureDesc;
	LockInfoListPtr lockInfos;
	TableAttributeValListPtr objectPropertyValues;
	bool hasGeometryHull;
};
typedef std::vector<FeatureData> FeatureDataList;

} //namespace ClientUtils
} //namespace GST

BOOST_CLASS_EXPORT_KEY(GST::ClientUtils::PropertyAlias);

BOOST_CLASS_VERSION(GST::ClientUtils::PropertyAlias, 1)

#endif // _NetworkInterfaceStructs_h_
